import os
import re
import random
import time
from tokenize import TokenError
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from drf_yasg.utils import swagger_auto_schema
from rest_framework import viewsets, status
from rest_framework.filters import SearchFilter
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_simplejwt.exceptions import InvalidToken
from rest_framework_simplejwt.token_blacklist.models import OutstandingToken, BlacklistedToken
from rest_framework_simplejwt.views import TokenObtainPairView
from django.http import FileResponse
from FreshMart import settings
from common.permission import IsAdminOrSelf, AddrIsAdminOrSelf
from .models import Users, Addr, VerifyCode
from .serializer import RegisterSerializer, UserProfileSerializer, AddressSerializer, AvatarSerializer, VerifySerializer
from common.aliyun_message import AliyunMessage
from rest_framework.throttling import AnonRateThrottle
from django.conf import settings
from django.http import JsonResponse
from alipay import AliPay


class VerifCodeView(APIView):
    """处理验证码相关操作的视图类"""
    throttle_classes = [AnonRateThrottle,]  # 限制未认证用户的请求频率

    def post(self, request):
        """处理 POST 请求以发送短信验证码"""
        # 获取手机号
        mobile = request.data.get('mobile')

        # 验证手机号的格式
        res = re.match(r'^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$', mobile)
        if not res:
            # 如果手机号格式不正确，返回 400 错误
            return Response({'error': "您输入的手机号码不符合规范"}, status=status.HTTP_400_BAD_REQUEST)

        # 随机生成验证码
        code = self.get_random_code()

        # 发送短信验证码
        result = AliyunMessage().send_msg(mobile, code)

        # 判断短信发送结果
        if result['code'] == 'NO':
            # 如果发送失败，返回 400 错误和错误信息
            return Response(result, status=status.HTTP_400_BAD_REQUEST)

        # 如果发送成功，将验证码保存到数据库
        ser = VerifySerializer(data={'code': code, 'mobile': mobile})
        if ser.is_valid():
            obj = ser.save()  # 保存验证码到数据库
            # 将验证码记录的 ID 返回到客户端
            result['code_id'] = obj.id
            return Response(result, status=status.HTTP_201_CREATED)
        else:
            # 如果序列化器验证失败，返回错误信息
            return Response({'error': ser.errors}, status=status.HTTP_400_BAD_REQUEST)

    def get_random_code(self):
        """随机生成 6 位验证码"""
        code = ''
        for _ in range(6):  # 循环生成 6 位数字
            i = random.choice(range(10))  # 从 0 到 9 中随机选择一个数字
            code += str(i)  # 将数字添加到验证码字符串中
        return code
class RegisterView(viewsets.ViewSet):
    # 注册视图，处理用户注册请求
    @swagger_auto_schema(request_body=RegisterSerializer)
    def create(self, request):
        """处理用户注册请求"""
        ser = RegisterSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'msg': '注册成功'}, status=status.HTTP_200_OK)
        else:
            return Response(ser.errors, status=status.HTTP_400_BAD_REQUEST)
class LoginView(TokenObtainPairView):
    # 登录视图，处理用户登录请求并返回 JWT Token
    @swagger_auto_schema(request_body=UserProfileSerializer)
    def post(self, request, *args, **kwargs):
        """处理用户登录请求并返回 JWT Token"""
        serializer = self.get_serializer(data=request.data)

        try:
            serializer.is_valid(raise_exception=True)
        except TokenError as e:
            raise InvalidToken(e.args[0])

        result = serializer.validated_data
        user = serializer.user

        # 更新响应数据，返回用户信息和 Token
        response_data = {
            'id': user.id,
            'phone_number': getattr(user, 'phone_number', None),
            'email': user.email,
            'username': user.username,
            'token': result.get('access'),
            'refresh': result.get('refresh'),
        }

        return Response({'msg': response_data}, status=status.HTTP_200_OK)
class LogoutView(APIView):
    # 登出视图，处理用户登出请求，将 JWT Token 加入黑名单
    permission_classes = [IsAuthenticated]

    def post(self, request):
        """处理用户登出请求，将 JWT Token 加入黑名单"""
        try:
            refresh_token = request.data.get("refresh_token")
            if refresh_token is not None:
                token = OutstandingToken.objects.get(token=refresh_token)
                # 将该 token 加入黑名单
                BlacklistedToken.objects.get_or_create(token=token)
            return Response({"msg": "退出成功"}, status=200)
        except Exception as e:
            return Response({"msg": "退出失败", "error": str(e)}, status=400)
class UserView(viewsets.ModelViewSet):
    # 用户视图集，处理用户的增删改查操作
    queryset = Users.objects.all()
    serializer_class = UserProfileSerializer
    permission_classes = (IsAuthenticated, IsAdminOrSelf)  # 默认权限设置

    def get_queryset(self):
        """根据用户角色返回不同的查询集"""
        user = self.request.user
        if user.is_superuser:
            return Users.objects.all()  # 超级管理员可以查看所有用户
        else:
            return Users.objects.filter(id=user.id)  # 普通用户只能查看自己的信息

    def retrieve(self, request, pk=None, *args, **kwargs):
        """自定义 retrieve 方法，根据用户角色设置权限"""
        if request.user.is_superuser:
            self.permission_classes = [IsAdminUser]  # 超级管理员查看用户信息
        else:
            self.permission_classes = [IsAuthenticated]  # 普通用户查看自己的信息
        return super().retrieve(request, *args, **kwargs)

    def upload_avatar(self, request, *args, **kwargs):
        """上传用户头像"""
        avatar = request.FILES.get('avatar')  # 使用 FILES 获取上传的文件
        if not avatar:
            return Response({'msg': '文件不能为空'}, status=400)
        if avatar.size > 1024*300:
            return Response({'msg': '文件不能超过300kb，请重新上传'}, status=400)
        user = request.user
        user.avatar = avatar  # 直接更新用户的 avatar 字段
        user.save()
        return Response({'msg': '头像上传成功'})

    def get_avatar(self, request, name):
        """获取用户头像"""
        path = os.path.join(settings.MEDIA_ROOT, name)
        if not os.path.exists(path):
            return Response({'msg': '文件不存在'}, status=404)
        response = FileResponse(open(path, 'rb'))
        return response

    def update_name(self, request, *args, **kwargs):
        """用户更改昵称"""
        last_name = self.request.data.get('last_name')
        if not last_name:
            return Response({'msg': '昵称不能输入空字符'}, status=status.HTTP_204_NO_CONTENT)

        user = self.get_object()
        user.last_name = last_name
        user.save()
        return Response({'msg': '昵称更改成功'}, status=status.HTTP_200_OK)

    def update_email(self, request, *args, **kwargs):
        """用户更改邮箱"""
        user = self.get_object()
        email = self.request.data.get('email')

        if not email:
            return Response({"msg": '邮箱不能为空'})
        if not re.match(r'^\w+@[A-Za-z]+(\.[A-Za-z0-9]+){1,}$', email):
            return Response({'error': "邮箱格式有误！"}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        if email == user.email:
            return Response({'msg': '邮箱和原邮箱相同'}, status=status.HTTP_204_NO_CONTENT)
        if self.get_queryset().filter(email=email).exclude(id=user.id).exists():
            return Response({'msg': "邮箱已经被其他账号绑定"}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)

        user.email = email
        user.save()
        return Response({'message': "邮箱更改成功"}, status=status.HTTP_200_OK)
class BindorUnbindView(viewsets.ViewSet):
    # 绑定手机号
    queryset = Users.objects.all()
    serializer_class = UserProfileSerializer
    permission_classes = [IsAuthenticated, IsAdminOrSelf]

    def bind_mobile(self, request, *args, **kwargs):
        """绑定手机号视图"""
        code = request.data.get('code')
        code_id = request.data.get('code_id')
        mobile = request.data.get('mobile')
        if not code:
            return Response({'error': "验证码不能为空"}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        if not mobile:
            return Response({'error': "手机号不能为空"}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        try:
            obj = VerifyCode.objects.get(id=code_id, code=code, mobile=mobile)
        except Exception as e:
            return Response({'msg': f'验证码错误，请重新获取验证码{e}'})
        # 检查验证码是否过期 (过期时间5分钟)
        if time.time() > obj.expiration.timestamp():
            obj.delete()
            return Response({'msg': '验证码已过期，请重新获取验证码'})
        # 绑定手机号
        # 校验手机号是否已绑定其他用户
        user = request.user
        user.phone_number = mobile
        user.save()
        obj.delete()
        return Response({'msg': '手机号绑定成功'}, status=status.HTTP_200_OK)

    def unbind_mobile(self, request, *args, **kwargs):
        """解绑手机号视图"""
        user = request.user
        mobile = user.phone_number
        code = request.data.get('code')
        if not code:
            return Response({'error': "验证码不能为空"}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        if not mobile:
            return Response({'error': "手机号不能为空"}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        try:
            obj = VerifyCode.objects.get(code=code, mobile=mobile)
        except Exception as e:
            return Response({'msg': f'验证码错误，请重新获取验证码{e}'})
        # 检查验证码是否过期 (过期时间5分钟)
        if time.time() > obj.expiration.timestamp():
            obj.delete()
            return Response({'msg': '验证码已过期，请重新获取验证码'})
        user.phone_number = ''
        user.save()
        obj.delete()
        return Response({'msg': '解绑成功'}, status=status.HTTP_200_OK)
class AddressView(viewsets.ModelViewSet):
    """用户地址视图集"""
    queryset = Addr.objects.all()
    serializer_class = AddressSerializer
    permission_classes = [IsAuthenticated, AddrIsAdminOrSelf]
    filter_backends = [SearchFilter]
    search_fields = ['user__username', 'user__phone_number']  # 根据用户名和手机号字段进行搜索

    def perform_create(self, serializer):
        """重写创建方法，将当前用户设置为地址的所有者"""
        serializer.save(user=self.request.user)

    def list(self, request, *args, **kwargs):
        """重写 list 方法，管理员可以查看所有用户的地址，普通用户只能查看自己的地址"""
        queryset = self.filter_queryset(self.get_queryset())

        user = self.request.user
        if user.is_superuser:
            queryset = Addr.objects.all()
        else:
            queryset = Addr.objects.filter(user=user)
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

    def set_default_addr(self, request, *args, **kwargs):
        """设置默认地址"""
        obj = self.get_object()
        obj.is_default = True
        obj.save()
        # 将该用户的其他地址设为非默认
        queryset = self.get_queryset().filter(user=self.request.user)
        for item in queryset:
            if item != obj:
                item.is_default = False
                item.save()
        return Response({'msg': '设置成功'}, status=status.HTTP_200_OK)
class AlipayPaymentView(APIView):
    def get(self, request):
        # 创建 AliPay 对象
        alipay = AliPay(
            appid=settings.ALIPAY_APP_ID,
            app_private_key_string=settings.ALIPAY_APP_PRIVATE_KEY_STRING,
            alipay_public_key_string=settings.ALIPAY_ALIPAY_PUBLIC_KEY_STRING,
            sign_type="RSA2",  # 使用 RSA2 签名算法
            debug=settings.ALIPAY_DEBUG  # 沙箱模式
        )

        # 订单信息
        order_id = "20240811"  # 测试订单号，可以使用动态生成的订单号
        total_amount = 100.00  # 订单总金额，单位为元
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=order_id,
            total_amount=str(total_amount),
            subject="Test Order",
            return_url=settings.ALIPAY_RETURN_URL,  # 同步回调 URL
            notify_url=settings.ALIPAY_NOTIFY_URL  # 异步通知 URL
        )

        # 支付宝沙箱支付网关地址
        alipay_url = f"https://openapi-sandbox.dl.alipaydev.com/gateway.do?{order_string}"
        return JsonResponse({"alipay_url": alipay_url})

class AlipayNotifyView(APIView):
    @method_decorator(csrf_exempt)
    def post(self, request):
        # 获取支付宝POST的数据
        data = request.POST.dict()
        alipay = AliPay(
            appid=settings.ALIPAY_APP_ID,
            app_notify_url=settings.ALIPAY_NOTIFY_URL,
            app_private_key_string=settings.ALIPAY_APP_PRIVATE_KEY_STRING,
            alipay_public_key_string=settings.ALIPAY_ALIPAY_PUBLIC_KEY_STRING,
            sign_type="RSA2",
            debug=settings.ALIPAY_DEBUG
        )

        # 验证签名
        signature = data.pop("sign")
        success = alipay.verify(data, signature)

        if success:
            # 处理支付成功的逻辑，例如更新订单状态
            return Response({"msg": "success"})
        else:
            return Response({"msg": "fail"}, status=400)

class AlipayReturnView(APIView):
    def get(self, request):
        # 同步回调的处理逻辑（用户支付成功后的页面）
        return Response({"msg": "支付成功"})